/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.service.impl;

import com.alicp.jetcache.anno.Cached;
import com.bifrost.common.util.HttpRequestUtils;
import com.bifrost.constant.AssociationType;
import com.bifrost.constant.InventoryType;
import com.bifrost.constant.PricingModel;
import com.bifrost.constant.ProductSkuType;
import com.bifrost.dto.AssignedProductOptionDTO;
import com.bifrost.entity.Media;
import com.bifrost.entity.Product;
import com.bifrost.entity.ProductOption;
import com.bifrost.entity.ProductOptionValue;
import com.bifrost.entity.ProductOptionXref;
import com.bifrost.entity.ProductService;
import com.bifrost.entity.ProductSku;
import com.bifrost.entity.SkuAssociation;
import com.bifrost.entity.SkuBundleItem;
import com.bifrost.entity.SkuMediaMap;
import com.bifrost.entity.SkuOptionValue;
import com.bifrost.model.SkuModel;
import com.bifrost.model.vo.ImgVo;
import com.bifrost.model.vo.PageVO;
import com.bifrost.model.vo.ProductSkuVO;
import com.bifrost.repository.ProductRepository;
import com.bifrost.repository.ProductServiceRepository;
import com.bifrost.repository.ProductSkuRepository;
import com.bifrost.repository.SkuAssociationRepository;
import com.bifrost.repository.SkuMediaMapRepository;
import com.bifrost.service.InventoryService;
import com.bifrost.service.ProductSkuService;
import com.bifrost.service.SkuMediaMapService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.ejb.QueryHints;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author joewee
 * @version 1.0.0
 * @Date 2017/10/29 13:49
 */
@Service
@Slf4j
public class ProductSkuServiceImpl implements ProductSkuService {
    private static final Logger logger = LoggerFactory.getLogger(ProductSkuServiceImpl.class);
    @Autowired
    SkuAssociationRepository skuAssociationRepository;
    @Autowired
    ProductSkuRepository productSkuRepository;
    @Autowired
    SkuMediaMapService skuMediaMapService;
    @Autowired
    SkuMediaMapRepository skuMediaMapRepository;
    @Autowired
    InventoryService inventoryService;
    @Autowired
    ProductServiceRepository productServiceRepository;
    @Autowired
    ProductRepository productRepository;
    @Autowired
    com.bifrost.service.ProductService productService;

    @PersistenceContext
    protected EntityManager em;

    /**
     * 获取sku指定类型的所有附属品
     *
     * @param sku  sku
     * @param type GIFT-赠品、UPKEEP-保养搭配
     * @return
     */
    @Override
    public List<ProductSku> getAssociationsByType(ProductSku sku, String type) {
        if (AssociationType.SERVICE.equalsIgnoreCase(type)) {
            return null;
        }
        List<ProductSku> skus = new ArrayList<>();
        skuAssociationRepository.findAllByproductSkuIdAndAssociationType(sku.getSkuId(), type).forEach(skuAssociation -> skus.add(skuAssociation.getAssociationProductSku()));
        return skus;
    }

    /**
     * 获取sku所有附属服务
     *
     * @param sku sku
     * @return
     */
    @Override
    public List<ProductService> getAssociationsOfService(ProductSku sku) {
        List<ProductService> services = new ArrayList<>();
        skuAssociationRepository.findAllByproductSkuIdAndAssociationType(sku.getSkuId(), AssociationType.SERVICE).forEach(skuAssociation -> services.add(skuAssociation.getProductService()));
        return services;
    }

    /**
     * 获取sku所有附属的保养搭配商品
     *
     * @param sku
     * @return
     */
    @Override
    public List<ProductSku> getAssociationsOfUpkeep(ProductSku sku) {
        return getAssociationsByType(sku, AssociationType.UPKEEP);
    }

    /**
     * 获取sku所有的附属礼品
     *
     * @param sku
     * @return
     */
    @Override
    public List<ProductSku> getAssociationsOfGift(ProductSku sku) {
        return getAssociationsByType(sku, AssociationType.GIFT);
    }

    /**
     * 检查sku是否可用
     *
     * @param sku
     * @return
     */
    @Override
    public boolean isAvailable(ProductSku sku) {
        if (sku == null) {
            return false;
        }
        if (/*Boolean.TRUE.equals(sku.isArchived()) || */Boolean.FALSE.equals(sku.isAvailable())) {
            return false;
        }

        if (!sku.isActive()) {
            return false;
        }
        Product product = sku.getProduct();
        if (Boolean.TRUE.equals(product.isArchived()) || Boolean.FALSE.equals(product.isAvailable())) {
            return false;
        }
        if (InventoryType.UNAVAILABLE.equals(sku.getInventoryType())) {
            return false;
        }
        if (InventoryType.CHECK_QUANTITY.equalsIgnoreCase(sku.getInventoryType())) {
            Integer stock = inventoryService.getInventoryBySkuId(sku.getSkuId());
            if (stock == null || stock <= 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 查询id对应的sku商品
     *
     * @param id skuId
     * @return
     */
    @Override
    public ProductSku getSkuById(Long id) {
        return productSkuRepository.findOne(id);
    }

    /**
     * 查询商品sku默认图片
     *
     * @param sku
     * @return
     */
    @Override
    public Media getSkuDefaultMedia(ProductSku sku) {
        return skuMediaMapService.getDefaultPrimaryMedia(sku);
    }

    /**
     * 返回sku主要图片
     *
     * @param productSku
     * @return
     */
    @Override
    public List<String> getSkuPrimaryMedias(ProductSku productSku) {
        if(productSku != null) {
            List<Media> medias = skuMediaMapService.getPrimaryMedia(productSku);
            if (medias != null && !medias.isEmpty()) {
                //List images = medias.stream().map(Media::getUrl).collect(Collectors.toList());
                List images = medias.stream().map(media -> HttpRequestUtils.getUrl(media.getUrl())).collect(Collectors.toList());
                return images;
            }
            return null;
        }
        return null;
    }

    /**
     * 查询商品sku默认图片
     *
     * @param sku
     * @return
     */
    @Override
    @Cached(name = "Product:getSkuDefaultMeda:" , expire = 30000 ,
            key = "#sku.skuId")
    public String getSkuDefaultMeda(ProductSku sku) {
        Media media = getSkuDefaultMedia(sku);
        return media==null?null:HttpRequestUtils.getUrl(media.getUrl());
    }

    /**
     * 返回默认sku图片: 入参sku可为非默认sku
     *
     * @param sku
     * @return
     */
    @Override
    public String getDefaultSkuMedia(ProductSku sku) {
        if(Boolean.TRUE.equals(sku.isDefault())){
            return getSkuDefaultMeda(sku);
        }
        return getSkuDefaultMeda(sku.getProduct().getDefaultSku());
    }

    /**
     * 返回所有默认SKU PRIMARY图片
     *
     * @param sku
     * @return
     */
    @Override
    @Cached(name = "Product:getDefaultSkuPrimaryMedias:" , expire = 30000 ,
            key = "#sku.skuId"   )
    public List getDefaultSkuPrimaryMedias(ProductSku sku) {
        List<Media> medias = null;
        if(Boolean.TRUE.equals(sku.isDefault())){
            medias = skuMediaMapService.getPrimaryMedia(sku);
        }else {
            ProductSku defaultSku = sku.getProduct().getDefaultSku();
            medias = skuMediaMapService.getPrimaryMedia(defaultSku);
        }
        if(CollectionUtils.isNotEmpty(medias)){
            //return medias.stream().map(Media::getUrl).collect(Collectors.toList());
            return  medias.stream().map(media -> HttpRequestUtils.getUrl(media.getUrl())).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public Media getSkuDefaultMedia(Long skuId) {
        return skuMediaMapService.getDefaultPrimaryMedia(skuId);
    }

    /**
     * 保存sku
     *
     * @param sku
     * @return
     */
    @Override
    public ProductSku saveSku(ProductSku sku) {
        return productSkuRepository.save(sku);
    }

    /**
     * 计算绑定商品价格
     *
     * @param sku
     */
    @Override
    public void pricingBundleProduct(ProductSku sku) {
        if (ProductSkuType.BUNDLE.equalsIgnoreCase(sku.getItemType())) {
            if (PricingModel.BUNDLE.equalsIgnoreCase(sku.getPricingModel())) {
                sku.setSalePrice(sku.getSalePrice());
                BigDecimal price = BigDecimal.ZERO;
                List<SkuBundleItem> bundleItems = sku.getSkuBundleItems();
                for (SkuBundleItem skuBundleItem : bundleItems) {
                    BigDecimal itemPrice = skuBundleItem.getItemPrice();
                    if (itemPrice != null) {
                        price = price.add(itemPrice.multiply(BigDecimal.valueOf(skuBundleItem.getBundleQuantity())));
                    }
                }
                sku.setRetailPrice(price);
            } else {
                List<SkuBundleItem> bundleItems = sku.getSkuBundleItems();
                BigDecimal price = BigDecimal.ZERO;
                for (SkuBundleItem skuBundleItem : bundleItems) {
                    BigDecimal itemPrice = skuBundleItem.getItemPrice();
                    if (itemPrice != null) {
                        price = price.add(itemPrice.multiply(BigDecimal.valueOf(skuBundleItem.getBundleQuantity())));
                    }
                }
                sku.setSalePrice(price);
                sku.setRetailPrice(price);
            }
        }
    }

    /**
     * 获取sku相关赠品和服务
     *
     * @param sku sku
     * @return Map
     */
    @Override
    public Map getSkuGiftAndService(ProductSku sku) {

        Map<String, Object> skuAssociationMap = new HashMap<String, Object>(3);
        List<Map> giftList = new ArrayList<>();
        List<Map> serviceList = new ArrayList<>();

        List<SkuAssociation> associationList = skuAssociationRepository.findAllByProductSkuId(sku.getSkuId());
        if (associationList == null || associationList.isEmpty()) {
            return skuAssociationMap;
        }
        Map<String, List<SkuAssociation>> typeMap = associationList.stream().collect(groupingBy(SkuAssociation::getAssociationType));

        for (String type : typeMap.keySet()) {
            if (AssociationType.UPKEEP.equals(type)) {
                continue;
            }
            List<SkuAssociation> list = typeMap.get(type);
            list.forEach(skuAssociation -> {
                //赠品
                if (AssociationType.GIFT.equals(skuAssociation.getAssociationType())) {
                    Map giftMap = new HashMap(2);
                    ProductSku productSku = skuAssociation.getAssociationProductSku();
                    giftMap.put("skuId", productSku.getSkuId());
                    giftMap.put("skuName", productSku.getSkuName());
                    giftList.add(giftMap);
                }
                //服务
                if (AssociationType.SERVICE.equals(skuAssociation.getAssociationType())) {
                    Map serviceMap = new HashMap(2);
                    ProductService productService = productServiceRepository.findOne(skuAssociation.getProductService().getServiceId());
                    serviceMap.put("serviceId", productService.getServiceId());
                    serviceMap.put("serviceName", productService.getServiceName());
                    serviceList.add(serviceMap);
                }
            });
        }
        skuAssociationMap.put("gift", giftList);
        skuAssociationMap.put("service", serviceList);
        return skuAssociationMap;
    }

    /**
     * 增加商品累计销售数量
     *
     * @param skuId
     * @param quantity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public ProductSku incrementSalesQuantity(Long skuId, Integer quantity) {
        if(skuId!=null) {
            productSkuRepository.updateSaleCount(skuId, quantity);
        }
        return null;
    }

    /**
     * 减少商品累计销售数量
     *
     * @param skuId
     * @param quantity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public ProductSku decrementSalesQuantity(Long skuId, Integer quantity) {
        ProductSku sku = getSkuById(skuId);
        if (sku != null) {
            Long count = sku.getSaleCount();
            if (count == null || quantity.longValue() > count) {
                sku.setSaleCount(0L);
            } else {
                sku.setSaleCount(count - quantity.longValue());
            }
            return saveSku(sku);
        }
        return null;
    }

    /**
     * 获取商品对应的规格属性以及sku
     *
     * @param productId
     * @return
     */
    @Override
    public List<AssignedProductOptionDTO> findAssignedProductOptionsByProductId(Long productId) {
        Session session = em.unwrap(Session.class);
        Criteria criteria = session.createCriteria(SkuOptionValue.class);
        List dtoList = criteria
                .createAlias("productSku", "sku")
                .createAlias("productSku.product", "product")
                .createAlias("productOptionValue", "productOptionValue")
                .createAlias("productOptionValue.productOption", "productOption")
                .setProjection(Projections.distinct(
                        Projections.projectionList()
                                .add(Projections.property("product.productId"), "productId")
                                .add(Projections.property("productOption.attributeName"), "productOptionAttrName")
                                .add(Projections.property("productOptionValue"), "productOptionValue")
                                .add(Projections.property("productSku"), "sku")
                        )
                ).setResultTransformer(Transformers.aliasToBean(AssignedProductOptionDTO.class))
                .add(Restrictions.eq("product.productId", productId))
                .addOrder(Order.asc("productOption.attributeName")).list();
        List<AssignedProductOptionDTO> results = new ArrayList<>();
        for (Object o : dtoList) {
            AssignedProductOptionDTO dto = (AssignedProductOptionDTO) o;
            if (dto.getSku().isActive()) {
                results.add(dto);
            }
        }
        return results;
    }

    /**
     * 获取商品对应的规格属性以及sku
     *
     * @param product
     * @return
     */
    @Override
    public List<AssignedProductOptionDTO> findAssignedProductOptionsByProduct(Product product) {
        return findAssignedProductOptionsByProductId(product.getProductId());
    }

    /**
     * 商品某属性的计数
     *
     * @param productOptionId
     * @return
     */
    @Override
    public Long countProductsUsingProductOptionById(Long productOptionId) {
        TypedQuery<Long> query = getProductIdsUsingProductOptionByIdQuery(productOptionId, true);
        query.setHint(QueryHints.HINT_CACHEABLE, true);
        return query.getSingleResult();
    }

    /**
     * 查询所有具有某属性的商品id
     *
     * @param productOptionId
     * @param start
     * @param pageSize
     * @return
     */
    @Override
    public List<Long> findProductIdsUsingProductOptionById(Long productOptionId, int start, int pageSize) {
        TypedQuery<Long> query = getProductIdsUsingProductOptionByIdQuery(productOptionId, false);
        query.setFirstResult(start);
        query.setMaxResults(pageSize);
        query.setHint(QueryHints.HINT_CACHEABLE, true);
        return query.getResultList();

    }
    private TypedQuery<Long> getProductIdsUsingProductOptionByIdQuery(Long productOptionId, boolean count) {
        // Set up the criteria query that specifies we want to return Products
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<Long> criteria = builder.createQuery(Long.class);

        // The root of our search is ProductOptionXref
        Root<ProductOptionXref> productOptionXref = criteria.from(ProductOptionXref.class);
        Join<ProductOptionXref, Product> product = productOptionXref.join("product");
        Join<ProductOptionXref, ProductOption> productOption = productOptionXref.join("productOption");

        if (count) {
            criteria.select(builder.count(product));
        } else {
            // Product IDs are what we want back
            criteria.select(product.get("productId").as(Long.class));
        }
        criteria.distinct(true);

        List<Predicate> restrictions = new ArrayList<Predicate>();
        restrictions.add(productOption.get("productOptionId").in(Arrays.asList(productOptionId)));

        // Execute the query with the restrictions
        criteria.where(restrictions.toArray(new Predicate[restrictions.size()]));
        return em.createQuery(criteria);
    }

    /**
     * 获取sku多规格属性map
     * <p>
     * skus->获取sku列表包含规格属性,options->规格类目列表
     * </p>
     *
     * @param product
     * @return
     */
    @Override
    public Map getSkusMap(Product product) {
        Map result = new HashMap();
        List<AssignedProductOptionDTO> assignedProductOptionDTOList = findAssignedProductOptionsByProduct(product);
        if (CollectionUtils.isNotEmpty(assignedProductOptionDTOList)) {
            List<Map> skuList = new ArrayList<>(assignedProductOptionDTOList.size());
            List<Map> optionList = new ArrayList<>();
            List<String> optionIndexList = new ArrayList<>();
            Map<ProductSku,List<AssignedProductOptionDTO>> skuListMap = assignedProductOptionDTOList.stream().collect(Collectors.groupingBy(AssignedProductOptionDTO::getSku));
            skuListMap.keySet().forEach(productSku -> {
                Map sku = new HashMap();
                sku.put("id",productSku.getSkuId());
                sku.put("price",productSku.getSalePrice().multiply(BigDecimal.valueOf(100)));//单位分
                sku.put("stock_num",InventoryType.ALWAYS_AVAILABLE.equalsIgnoreCase(productSku.getInventoryType())?999999:productSku.getQuantityAvailable()==null?0:productSku.getQuantityAvailable());
                List<AssignedProductOptionDTO> dtos = skuListMap.get(productSku);
                for (int i=1;i<= dtos.size();i++) {
                    AssignedProductOptionDTO dto =dtos.get(i-1);
                    ProductOptionValue value = dto.getProductOptionValue();
                    Long id = value.getProductOptionValueId();
                    sku.put("s"+i,id);

                    String name = dto.getProductOptionAttrName();
                    if(!optionIndexList.contains(name)){
                        Map opt = new HashMap();
                        opt.put("k",dto.getProductOptionAttrName());
                        opt.put("v",new ArrayList<>());
                        opt.put("k_s","s"+i);
                        optionList.add(opt);
                        optionIndexList.add(dto.getProductOptionAttrName());
                    }
                    int index = optionIndexList.indexOf(name);
                    Map option =  (Map)optionList.get(index);
                    Map optValue = new HashMap(4);
                    optValue.put("id",value.getProductOptionValueId());
                    optValue.put("name",value.getAttributeValue());
                    //optValue.put("imgUrl","");
                    List optList = ((List)option.get("v"));
                    if(!optList.contains(optValue)){
                        optList.add(optValue);
                    }
                }
                skuList.add(sku);
            });
            result.put("skus",skuList);
            result.put("options",optionList);
        }
        return result;
    }

    /**
     * 获取所有sku，当商品有规格属性时过掉滤默认sku
     *
     * @param product
     * @return
     */
    @Override
    public List<SkuModel> getAllSku(Product product) {
        List<ProductSku> skus = product.getProductSkus();
        List<SkuModel> skuModels = new ArrayList<>();
        for (ProductSku sku : skus) {
            if(Boolean.TRUE.equals(sku.isDefault())){
                continue;
            }
            skuModels.add(convertToSkuModel(sku));
        }
        return skuModels;

    }

    /**
     * sku to skuModel
     *
     * @param sku
     * @return
     */
    @Override
    public SkuModel convertToSkuModel(ProductSku sku) {
        SkuModel skuModel = new SkuModel();
        skuModel.setSkuName(sku.getSkuName());
        skuModel.setSkuDescription(sku.getSkuDescription());
        Media media = getSkuDefaultMedia(sku);
        skuModel.setImage(media==null?null:HttpRequestUtils.getUrl(media.getUrl()));
        skuModel.setSkuId(sku.getSkuId());
        skuModel.setSalePrice(sku.getRetailPrice());
        skuModel.setPrice(sku.getSalePrice());
        skuModel.setCanAddCart(!Boolean.FALSE.equals(sku.getCanAddCart()));
        Boolean skuIsAvalible = sku.getAvailable();
        if(skuIsAvalible == null || Boolean.FALSE.equals(skuIsAvalible)){
            skuModel.setAvalible(false);
            skuModel.setUnAvalibleReson("商品已下架");
        }else {
            boolean stockIsAvalible = inventoryService.checkInventory(sku);
            skuModel.setAvalible(stockIsAvalible);
            if (!stockIsAvalible) {
                skuModel.setUnAvalibleReson("库存不足");
            }else{
                skuModel.setStockAvalible(sku.getQuantityAvailable());
                skuModel.setStock(sku.getQuantityAvailable());

                if(InventoryType.ALWAYS_AVAILABLE.equalsIgnoreCase(sku.getInventoryType())){
                    skuModel.setStock(999999);
                }else{
                    if(!Boolean.TRUE.equals(sku.isDefault())){
                        skuModel.setStock(sku.getQuantityAvailable());
                    }else{
                        Integer available = inventoryService.retrieveQuantityAvailable(sku.getProduct());
                        skuModel.setStock(available==null?0:available);
                    }
                }
            }
        }
        Map attrMap = new HashMap(4);
        List<SkuOptionValue> valueList = sku.getSkuOptionValues();
        valueList.forEach(skuOptionValue -> {
            ProductOptionValue optionValue = skuOptionValue.getProductOptionValue();
            ProductOption option = optionValue.getProductOption();
            attrMap.put(option.getAttributeName(), optionValue.getAttributeValue());
        });
        skuModel.setAttrs(attrMap);
        return skuModel;
    }

    /**
     * 返回默认sku
     *
     * @param productSkuId
     * @return
     */
    @Override
    public ProductSku getDefaultSku(Long productSkuId) {
        if(productSkuId != null){
            ProductSku sku = getSkuById(productSkuId);
            return getDefaultSku(sku);
        }
        return null;
    }

    /**
     * 返回默认sku
     *
     * @param productSku
     * @return
     */
    @Override
    public ProductSku getDefaultSku(ProductSku productSku) {
        if(productSku != null){
            if(Boolean.TRUE.equals(productSku.isDefault())){
                return productSku;
            }
            else {
                return productSku.getProduct().getDefaultSku();
            }
        }
        return null;
    }

    @Override
    public ProductSku getByExternalId(String externalId) {
        Assert.hasText(externalId,"外部系统id不能为空");
        return productSkuRepository.findFirstByExternalId(externalId);
    }

    @Override
    public PageVO findSkuHot(int page, int pageSize) {
        Pageable pageable=new PageRequest(page - 1,pageSize,new Sort(Sort.Direction.DESC,"updatedTimestamp"));

        Specification<ProductSku> query= new Specification<ProductSku>() {
            @Override
            public Predicate toPredicate(Root<ProductSku> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                List<Predicate> predicates = new ArrayList<>();

                //增加查询条件：排除已删除的
                predicates.add(criteriaBuilder.equal(root.get("sortHot"), true));

                predicates.add(criteriaBuilder.equal(root.get("available"), true));

                predicates.add(criteriaBuilder.equal(root.get("auditStatus"), "ON_SALE"));

                Join<Product,ProductSku> join = root.join("product", JoinType.INNER);

                predicates.add(criteriaBuilder.equal(join.get("archived"),false));

                Path<Boolean> isOffline = join.get("isOffline");
                predicates.add(criteriaBuilder.or(criteriaBuilder.isNull(isOffline),
                        criteriaBuilder.isFalse(isOffline)));

                Predicate[] p = new Predicate[predicates.size()];
                return criteriaBuilder.and(predicates.toArray(p));
            }
        };

        Page<ProductSku> data=productSkuRepository.findAll(query,pageable);
        List<ProductSku> productSkus=data.getContent();

        ArrayList<ProductSkuVO> vos=new ArrayList<>(productSkus.size());
        productSkus.stream().forEach(product -> {
            ProductSkuVO vo=new ProductSkuVO();
            BeanUtils.copyProperties(product,vo);
            //TODO 设置其他属性
            vo.setProductId(product.getProduct().getProductId());
            vo.setProductName(product.getProduct().getProductName());
            vo.setProductBrandName(product.getProduct().getProductBrand().getBrandName());
            vo.setBrandId(product.getProductBrandId());
            vo.setRetailPrice(product.getRetailPrice());
            vo.setSalePrice(product.getSalePrice());
            List<SkuMediaMap> skuMediaMaps=skuMediaMapRepository.findAllByProductSku(product.getSkuId());
            List<ImgVo> imgheader=new ArrayList<>(skuMediaMaps.size());
            List<ImgVo> imgdetail=new ArrayList<>(skuMediaMaps.size());
            skuMediaMaps.stream().forEach(skuMediaMap -> {
                if (skuMediaMap.getMapKey().contains("detail")){
                    ImgVo imgVo=new ImgVo();
                    imgVo.setUrl(HttpRequestUtils.getUrlAccessPath()+skuMediaMap.getImg());
                    imgdetail.add(imgVo);
                }else if (skuMediaMap.getMapKey().contains("main")){
                    ImgVo imgVo=new ImgVo();
                    imgVo.setUrl(HttpRequestUtils.getUrlAccessPath()+skuMediaMap.getImg());
                    imgheader.add(imgVo);
                }
            });
            vo.setImgheader(imgheader);
            vo.setImgdetail(imgdetail);
            if (imgheader.size()>0){
                vo.setUrl(imgheader.get(0).getUrl());
            }else {
                vo.setUrl("");
            }
            vos.add(vo);
        });

        PageVO pageVO=new PageVO(data.getNumber(),data.getSize(),(int)data.getTotalElements(),vos);
        return pageVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int updateSkuHot(String ids, Boolean hot) {

        String[] id =ids.split(",");
        ArrayList<Long> pids=new ArrayList<>(id.length);
        try {
            Arrays.stream(id).forEach(p->{
                pids.add(Long.valueOf(p));
            });
        } catch (Exception e) {
            e.printStackTrace();
            log.error("类型转换失败");
            return 0;
        }
        int i=productSkuRepository.updateProductSkuHot(pids,hot);
        return i;
    }

    /**
     * 返回sku规格描述、eg：黑色 / XXl
     *
     * @param productSkuId productSkuId
     * @return option
     */
    @Override
    public String getSkuOptions(Long productSkuId) {
        Session session = em.unwrap(Session.class);
        String sql = "SELECT o.PRODUCT_OPTION_VALUE_ID as `id`,o.ATTRIBUTE_VALUE as `name` FROM sku_option_value v left join product_option_value o on v.PRODUCT_OPTION_VALUE_ID=o.PRODUCT_OPTION_VALUE_ID WHERE v.SKU_ID='"+productSkuId+"'";
        List<Map<String, Object>> data = session.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
        if (CollectionUtils.isNotEmpty(data)) {
            data = data.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> String.valueOf(o.get("id"))))), ArrayList::new));
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.size(); i++) {
                sb.append(String.valueOf(data.get(i).get("name")));
                if(i < data.size() - 1)
                    sb.append("/");
            }
            return sb.toString();
        }else {
            return null;
        }
    }

}
